﻿using Corina.Events;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;

namespace Corina.Infrastructure
{
    [DataContract]
    public class BaseClass : NotificationObject
    {
        public Type EntityType
        {
            get { return this.GetType(); }
        }

        #region Properties
        public bool IsEnumProperty(string propertyName)
        {
            PropertyInfo property = EntityType.GetProperty(propertyName);
            return typeof(Enum).IsAssignableFrom(property.PropertyType);
        }

        public Type PropertyType(string propertyName)
        {
            PropertyInfo property = EntityType.GetProperty(propertyName);
            return property.PropertyType;
        }

        public bool ExistProperty(string propertyName)
        {
            return EntityType.GetProperty(propertyName) != null;
        }

        /// <summary>
        /// Get value of property.
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <returns></returns>
        public object GetPropertyValue(string propertyName)
        {
            PropertyInfo propertyInfo = EntityType.GetProperty(propertyName);
            if (propertyInfo == null)
            {
                return null;
            }
            else
            {
                return propertyInfo.GetValue(this, null);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public object GetPropertyValue<T>(Expression<Func<T>> expression)
        {
            var propertyName = PropertySupport.ExtractPropertyName(expression);
            return GetPropertyValue(propertyName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        public void SetPropertyValue(string propertyName, object value)
        {
            PropertyInfo property = EntityType.GetProperty(propertyName);
            if (property != null && property.CanWrite)
            {
                if (value != null && !string.IsNullOrEmpty(value.ToString()))
                {
                    bool isEnum = typeof(Enum).IsAssignableFrom(property.PropertyType);
                    if (isEnum)
                    {
                        if (value.GetType() != typeof(string))
                        {
                            value = Enum.GetName(property.PropertyType, value);
                        }
                        value = Enum.Parse(property.PropertyType, value.ToString(), true);
                    }
                    property.SetValue(this, Convert.ChangeType(value, property.PropertyType, CultureInfo.CurrentCulture), null);
                }
                else
                {
                    property.SetValue(this, null, null);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="value"></param>
        public void SetPropertyValue<T>(Expression<Func<T>> expression, object value)
        {
            var propertyName = PropertySupport.ExtractPropertyName(expression);
            SetPropertyValue(propertyName, value);
        }

        public object this[string name]
        {
            get
            {
                return GetPropertyValue(name);
            }
            set
            {
                SetPropertyValue(name, value);
                RaisePropertyChanged(name);
            }
        }
        #endregion

        #region Events
        public event EventHandler<PropertyArgs> ValueChanged = delegate { };

        protected override void RaisePropertyChanged(string propertyName)
        {
            base.RaisePropertyChanged(propertyName);
            if (ValueChanged != null)
            {
                ValueChanged.Invoke(this, new PropertyArgs()
                {
                    Property = GetType().GetProperty(propertyName),
                    Value = GetType().GetProperty(propertyName).GetValue(this, null)
                });
            }
        }
        #endregion
    }
}
